package com.zhanglijie.improve.aqs.share.semaphore;

import java.security.InvalidParameterException;

import com.zhanglijie.improve.aqs.exclusive.MyAbstractQueuedSynchronizer;

/**
 * @author zhanglijie
 * @version 1.0
 * @since 1.1.0 2022/10/4 0004 17:13
 */
public class MySemaphore {
    private final MySync sync;

    /**
     * 无参默认构造方法是 非公平锁
     */
    public MySemaphore(int permits) {
        sync = new MyUnFairSync(permits);

    }
    public MySemaphore(boolean isFair,int permits){
        sync = isFair?new MyFairSync(permits):new MyUnFairSync(permits);
    }

    /**
     * 公平/非公平锁 ->MySync->MyAbstractQueuedSynchronized
     */
    abstract static class MySync extends MyAbstractQueuedSynchronizer {
       public MySync(int permits){
           setState(permits);
       }
       public int getPermits(){
           return getState();
       }

       @Override
       protected boolean tryReleaseShared(int arg){
           for(;;){
               int current = getState();
               int next = current+arg;
               if(next < current){//表明传的arg为负数不合理
                  throw new InvalidParameterException("参数异常");
               }
               if(compareAndSetState(current,next)){
                   return true;
               }
           }
       }

    }

    /**
     * 公平锁
     */
    static class MyFairSync extends  MySync {

        public MyFairSync(int permits) {
            super(permits);
        }

        /**
         * 公平锁尝试获取
         * @param arg
         * @return
         */

        @Override
        protected int tryAcquireShared(int arg){
            for(;;){//自旋操作，这个是和独占锁（ReentrantLock)有区别的地方
               //公平锁多个base-case：如果有人排队了 直接return -1让你也去排队去
                if(hasQueuePred()){
                    return -1;
                }
                int state = getState();
                int i = state-arg;
                if(i<0 || compareAndSetState(state,i)){
                    return i;
                }
            }
        }
    }

    /**
     * 非公平锁
     */
    static class MyUnFairSync extends MySync {

        public MyUnFairSync(int permits) {
            super(permits);
        }

        /**
         * 非公平锁尝试
         * @param arg
         * @return
         */
        @Override
        protected int tryAcquireShared(int arg){
           for(;;){//自旋操作，这个是和独占锁（ReentrantLock)有区别的地方  之所以自旋 是因为state还可以拿
               int state = getState();
               int i = state-arg;
               if(i<0 || compareAndSetState(state,i)){
                   return i;
               }
           }
        }
    }

    public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);//todo 为啥这个用中断的方法不用acquireShared 和下面的相反  它和reentrantLock相反
    }

    /**
     * 共享锁（不响应中断）
     */
    public void acquireUnInterruptibly(){
        sync.acquireShared(1);
    }


    public void release(){
        sync.releaseShared(1);
    }

}
